package com.handydata.antifraud.rule;

import com.handydata.antifraud.dao.RiskRuleDictlinfoBasedataDao;
import com.handydata.antifraud.entity.RiskRuleDictIinfoDao;
import com.handydata.antifraud.enums.RiskRuleDictEnum;
import com.handydata.antifraud.port.Arithmetic;
import com.handydata.antifraud.port.RuleEngineInvokers;
import com.handydata.antifraud.ws.EncryInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;

@Component
@Slf4j
public class RuleEngineInvokerFactory {
    private static ConcurrentHashMap<String, RuleEngineInvoker> ruleEngineInvokerContainers = new ConcurrentHashMap<>();

    @Autowired
    private RiskRuleDictlinfoBasedataDao riskRuleDictlinfoBasedataDao;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private EncryInfo encryInfo;

    @Autowired
    private RuleEngineInvokers ruleEngineInvokers;

    @Autowired
    private Arithmetic arithmetic;



    /**
     * 取得规则引擎调用器
     * @param key
     * @return
     */
    public RuleEngineInvoker getRuleEngineInvoker(String key) throws ExecutionException, InterruptedException {
        RiskRuleDictIinfoDao riskRuleDictIinfoDao =  new RiskRuleDictIinfoDao();
        riskRuleDictIinfoDao.setStatus("1");
        long countRiskRule = riskRuleDictlinfoBasedataDao.count(riskRuleDictIinfoDao);
        if(new Long(ruleEngineInvokerContainers.size()) != countRiskRule){
            ruleEngineInvokerContainers = new ConcurrentHashMap<>();
            log.info("缓存不同步,正在同步中,稍等..........");
            List<Map<String, String>> riskRuleList = riskRuleDictlinfoBasedataDao.queryOrderList();
            if(riskRuleList.isEmpty()){
                return null;
            }
            this.init(riskRuleList);
        }
        log.info("缓存数据:{}", ruleEngineInvokerContainers.size());
        log.info("缓存数据:{}", ruleEngineInvokerContainers.toString());
        return ruleEngineInvokerContainers.get(key);
    }

    /**
     * 刷新规则引擎规则文件
     * @param packages
     * @return
     */
    public void refreshRulePackage(List<String> packages) {
        for(RuleEngineInvoker invoker:ruleEngineInvokerContainers.values()){
            if(packages.contains(invoker.getPackageName())){
                log.info("开始刷新规则:{}",invoker.getPackageName());
                invoker.refreshPackage();
            }
        }
    }

    /**
     * 初始化
     * @param packages
     */
    public void init(List<Map<String, String>> packages) {
        if(CollectionUtils.isNotEmpty(packages)) {
            packages.stream().forEach(pak -> ruleEngineInvokerContainers.putIfAbsent(combineKey(pak), createRuleEngineInvoker(pak)));
        }
    }

    private String combineKey(Map<String, String> map) {
        String productCode = require(map.get("product_code"));
        String custTypeCode = require(map.get("cust_type_code"));
        String decisionScenario = require(map.get("process_decision_scenario"));
        return productCode + custTypeCode + decisionScenario;
    }

    private RuleEngineInvoker createRuleEngineInvoker(Map<String, String> map) {
        String packageName = require(map.get("package_name"));
        String processName = require(map.get("process_name"));
        return new RuleEngineInvoker(packageName, processName);
    }
    private <T> T require(T t) {
        Objects.requireNonNull(t);
        return t;
    }


}
